import os
import numpy as np
import logging
from matplotlib import pyplot as plt
from datetime import datetime
from numpy import ndarray
from typing import Dict, List, Union


class LoggerConfig:
    def __init__(self):
        self.logger = logging.getLogger("augment_log")
        log_filename = Constants().log_filename
        self.logger.setLevel(logging.INFO)
        consoleHandler = logging.StreamHandler()
        fileHandler = logging.FileHandler(log_filename, mode="a", encoding="utf8")
        fmt = logging.Formatter("%(asctime)s | %(levelname)s | %(filename)s:%(lineno)s | %(message)s")
        consoleHandler.setFormatter(fmt)
        fileHandler.setFormatter(fmt)
        self.logger.addHandler(consoleHandler)
        self.logger.addHandler(fileHandler)

    def get_logger(self):
        return self.logger


class Constants:
    def __init__(self):
        self._base_dir = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
        self._data_base_dir = os.path.join(self._base_dir, "data")
        self._each_sample_augment_count: int = 20  # 每个原始样本扩充几个样本
        self._origin_path: str = os.path.join(self._data_base_dir, "origin")  # 原始数据存放的路径
        self._augment_path: str = os.path.join(self._data_base_dir, "data_augment")  # 数据扩充存放的路径
        self._log_path: str = os.path.join(self._base_dir, "log")
        dt = datetime.now()
        self._log_filename: str = os.path.join(self._log_path, "{}.log".format(dt.date()))
        self._labels: List[str] = ["Isophthalic Acid", "Phthalic Acid", "Polyethylene", "Terephthalic Acid", "Trehalose"]
        self._filenames: Dict[str: Dict[str, str]] = {
            "origin": {k: k + ".csv" for k in self._labels},
            "augment": {k: "augment_" + k + ".csv" for k in self._labels}
        }
        self._img_path: str = os.path.join(self._base_dir, "img")
        self._img_filenames: Dict[str: Dict[str, str]] = {
            "origin": {k: "origin_" + k + ".svg" for k in self._labels},
            "augment": {k: "augment_" + k + ".svg" for k in self._labels}
        }
        self._cos_distance: Dict[str, float] = {"low": 0.0001, "high": 2.0}
        self._eucli_distance: Dict[str, float] = {"low": 0.0001, "high": 2.0}

    @property
    def each_sample_augment_count(self) -> int:
        return self._each_sample_augment_count

    @property
    def origin_path(self) -> str:
        return self._origin_path

    @property
    def augment_path(self) -> str:
        return self._augment_path

    @property
    def filenames(self):
        return self._filenames

    @property
    def base_dir(self):
        return self._base_dir

    @property
    def data_base_dir(self):
        return self._data_base_dir

    @property
    def img_path(self):
        return self._img_path

    @property
    def img_filenames(self):
        return self._img_filenames

    @property
    def cos_distance(self):
        return self._cos_distance

    @property
    def eucli_distance(self):
        return self._eucli_distance

    @property
    def labels(self):
        return self._labels

    @property
    def log_path(self):
        return self._log_path

    @property
    def log_filename(self):
        return self._log_filename


class Distance:
    def __init__(self, a: ndarray, b: ndarray):
        """
        :param a: ndarray, one vector
        :param b: ndarray, another vector
        """

        self._vector1 = a
        self._vector2 = b

    def cosine(self):
        """
        @returns: Cosine distance: float
        """
        return 1.0 - (self._vector1 @ self._vector2) / (np.linalg.norm(self._vector1) * np.linalg.norm(self._vector2))

    def euclid(self):
        """
        @returns: Euclid distance: float
        """
        return np.linalg.norm(self._vector1 - self._vector2)


class MoveRandom:
    def __init__(self, row, step: int = 1):
        self._row = row
        if step > len(row):
            step = len(row)
        self._step = step

    def _move_left(self):
        step = (-1) * self._step
        for i in range(0, len(self._row) - step, 1):
            self._row[i] = self._row[i + step]
        for i in range(len(self._row) - 1, len(self._row) - step - 1, -1):
            self._row[i] = 0
        return self._row

    def _move_right(self):
        for i in range(len(self._row) - self._step - 1, -1, -1):
            self._row[i + self._step] = self._row[i]
        for i in range(0, self._step, 1):
            self._row[i] = 0
        return self._row

    def random_move(self):
        if self._step < 0:
            return self._move_left()
        elif self._step > 0:
            return self._move_right()
        else:
            return self._row


def plot_spectrum(data_to_plot: Union[ndarray], filepath: str, title: str) -> None:
    plt.rcParams['xtick.direction'] = 'in'
    plt.rcParams['ytick.direction'] = 'in'
    plt.rc('font', family='Times New Roman')
    samples_count = len(data_to_plot)
    length = data_to_plot.shape[1]
    x = np.linspace(0.9, 6.0, length)
    for row in range(samples_count):
        plt.plot(x, data_to_plot[row, :])
    plt.title(title)
    # x_left, x_right = plt.xlim()
    # y_bottom, y_top = plt.ylim()
    # plt.text(x_left + (x_right - x_left) / 20, y_top - (y_top - y_bottom) / 10, title)
    plt.xlabel('Frequency (THz)')
    plt.ylabel('Absorbance ($cm^{-1}$)')
    plt.savefig(filepath)
    plt.show()


if __name__ == '__main__':
    x = np.array([1, 2, 3, 4, 5, 6])
    move = MoveRandom(x, 7)
    print(move.random_move())



















